#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
死代码注入器
向代码中注入永远不会执行的分支和逻辑，增加逆向分析难度
"""

import os
import random
import re
from pathlib import Path
from typing import List, Optional, Tuple

from core.builtin_config_module.builtin_config import BuiltInConfig
from core.utils_module.language_utils import detect_language_for_file
from core.utils_module.logger import ObfuscationLogger


class DeadCodeInjector:
    """死代码注入器 - 注入不可达代码分支"""

    # 复杂度配置
    COMPLEXITY_CONFIG = {
        'low': {
            'branches_per_function': 1,
            'max_depth': 1,
            'use_opaque_predicates': False
        },
        'medium': {
            'branches_per_function': 2,
            'max_depth': 2,
            'use_opaque_predicates': True
        },
        'high': {
            'branches_per_function': 3,
            'max_depth': 3,
            'use_opaque_predicates': True
        }
    }

    def __init__(self, config: BuiltInConfig, logger: ObfuscationLogger):
        """
        初始化死代码注入器

        Args:
            config: 统一配置对象
            logger: 日志记录器
        """
        self.config = config
        self.logger = logger
        self.injected_count = 0

    def inject_to_project(self, project_path: str,
                         complexity: Optional[str] = None,
                         probability: Optional[float] = None) -> bool:
        """
        向项目注入死代码

        Args:
            project_path: 项目路径
            complexity: 复杂度 low/medium/high
            probability: 注入概率 (0.0-1.0)

        Returns:
            是否成功
        """
        try:
            # 使用参数或配置
            complexity = (
                complexity
                if complexity is not None
                else self.config.advanced_features.dead_code_complexity
            )
            probability = (
                probability
                if probability is not None
                else self.config.advanced_features.dead_code_injection_probability
            )

            if project_path and not os.path.exists(project_path):
                self.logger.log_error(f"死代码注入失败: 项目路径不存在 {project_path}")
                return False

            self.logger.log_operation(
                "死代码注入",
                f"复杂度: {complexity}, 注入概率: {probability}"
            )

            # 查找目标文件
            target_files = self._find_target_files(project_path)

            if not target_files:
                self.logger.log_warning("没有找到目标文件")
                return False

            self.logger.log_operation("目标文件", f"找到 {len(target_files)} 个文件")

            # 注入死代码
            self.injected_count = 0
            for file_path in target_files:
                # 根据概率决定是否注入
                if random.random() < probability:
                    if self._inject_to_file(file_path, complexity):
                        self.injected_count += 1

            self.logger.log_operation(
                "死代码注入完成",
                f"成功注入 {self.injected_count} 个文件"
            )

            return True

        except Exception as e:
            self.logger.log_error(f"死代码注入失败: {e}")
            return False

    def _find_target_files(self, project_path: str) -> List[str]:
        """
        查找目标文件

        Args:
            project_path: 项目路径

        Returns:
            文件路径列表
        """
        target_files = []

        for root, dirs, files in os.walk(project_path):
            # 跳过隐藏目录和构建目录
            dirs[:] = [d for d in dirs if not d.startswith('.')
                      and d not in ['build', 'dist', '__pycache__', 'node_modules', 'DummyCode']]

            for file in files:
                file_path = os.path.join(root, file)
                language = detect_language_for_file(file_path)

                # 只处理支持的语言
                if language in ['swift', 'java', 'kotlin']:
                    target_files.append(file_path)

        return target_files

    def _inject_to_file(self, file_path: str, complexity: str) -> bool:
        """
        向文件注入死代码

        Args:
            file_path: 文件路径
            complexity: 复杂度

        Returns:
            是否成功
        """
        try:
            # 读取文件内容
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()

            # 检测语言
            language = detect_language_for_file(file_path)

            # 查找函数
            functions = self._find_functions(content, language)

            if not functions:
                return False

            # 获取配置
            config = self.COMPLEXITY_CONFIG[complexity]

            # 对每个函数注入死代码
            modified_content = content
            offset = 0

            for func_name, func_start, func_end in functions:
                # 生成死代码
                dead_code = self._generate_dead_code(
                    language,
                    config['branches_per_function'],
                    config['use_opaque_predicates']
                )

                # 找到函数体的注入位置（函数开始后的第一行）
                injection_pos = func_start + offset

                # 插入死代码
                modified_content = (
                    modified_content[:injection_pos] +
                    dead_code +
                    modified_content[injection_pos:]
                )

                offset += len(dead_code)

            # 写回文件
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(modified_content)

            self.logger.log_file_processing(file_path, f"注入了 {len(functions)} 个死代码分支")
            return True

        except Exception as e:
            self.logger.log_warning(f"注入死代码失败 {file_path}: {e}")
            return False

    def _find_functions(self, content: str, language: str) -> List[Tuple[str, int, int]]:
        """
        查找文件中的函数定义

        Args:
            content: 文件内容
            language: 编程语言

        Returns:
            函数信息列表 [(函数名, 开始位置, 结束位置)]
        """
        functions = []

        if language == 'swift':
            # Swift: func functionName(...) {
            pattern = r'func\s+(\w+)\s*\([^)]*\)\s*(?:->\s*\w+\s*)?\{'
            matches = re.finditer(pattern, content)

            for match in matches:
                func_name = match.group(1)
                func_start = match.end()  # 函数体开始（{之后）
                func_end = self._find_closing_brace(content, func_start)
                functions.append((func_name, func_start, func_end))

        elif language == 'java':
            # Java: public/private/protected returnType functionName(...) {
            pattern = r'(?:public|private|protected|static)?\s+\w+\s+(\w+)\s*\([^)]*\)\s*\{'
            matches = re.finditer(pattern, content)

            for match in matches:
                func_name = match.group(1)
                func_start = match.end()
                func_end = self._find_closing_brace(content, func_start)
                functions.append((func_name, func_start, func_end))

        elif language == 'kotlin':
            # Kotlin: fun functionName(...) {
            pattern = r'fun\s+(\w+)\s*\([^)]*\)\s*(?::\s*\w+\s*)?\{'
            matches = re.finditer(pattern, content)

            for match in matches:
                func_name = match.group(1)
                func_start = match.end()
                func_end = self._find_closing_brace(content, func_start)
                functions.append((func_name, func_start, func_end))

        return functions

    def _find_closing_brace(self, content: str, start: int) -> int:
        """
        查找匹配的右大括号

        Args:
            content: 文件内容
            start: 开始位置

        Returns:
            右大括号位置
        """
        depth = 1
        i = start

        while i < len(content) and depth > 0:
            if content[i] == '{':
                depth += 1
            elif content[i] == '}':
                depth -= 1
            i += 1

        return i

    def _generate_dead_code(self, language: str, branch_count: int,
                           use_opaque: bool) -> str:
        """
        生成死代码

        Args:
            language: 编程语言
            branch_count: 分支数量
            use_opaque: 是否使用不透明谓词

        Returns:
            死代码字符串
        """
        dead_code_blocks = []

        for i in range(branch_count):
            if use_opaque:
                # 使用不透明谓词
                block = self._generate_opaque_predicate_block(language)
            else:
                # 使用简单的恒假条件
                block = self._generate_simple_dead_block(language)

            dead_code_blocks.append(block)

        return '\n'.join(dead_code_blocks)

    def _generate_opaque_predicate_block(self, language: str) -> str:
        """
        生成不透明谓词死代码块

        不透明谓词：数学上总是真或假，但难以静态分析

        Args:
            language: 编程语言

        Returns:
            死代码块
        """
        # 选择一个不透明谓词
        predicates = [
            # (x * x) % 2 总是 0 或 1
            "((tempVar * tempVar) % 2 == 0 || (tempVar * tempVar) % 2 == 1)",
            # x * (x + 1) 总是偶数
            "(tempVar * (tempVar + 1)) % 2 == 0",
            # 2x + 1 总是奇数
            "((2 * tempVar + 1) % 2) == 1"
        ]

        predicate = random.choice(predicates)

        if language == 'swift':
            return f"""
        // Dead code - opaque predicate
        let tempVar = Int.random(in: 1...100)
        if {predicate} {{
            // This code is never reached but appears reachable
            let deadVar = "{self._random_string(20)}"
            print(deadVar)
        }}
"""
        elif language == 'java':
            return f"""
        // Dead code - opaque predicate
        int tempVar = new java.util.Random().nextInt(100) + 1;
        if ({predicate}) {{
            // This code is never reached but appears reachable
            String deadVar = "{self._random_string(20)}";
            System.out.println(deadVar);
        }}
"""
        elif language == 'kotlin':
            return f"""
        // Dead code - opaque predicate
        val tempVar = (1..100).random()
        if ({predicate}) {{
            // This code is never reached but appears reachable
            val deadVar = "{self._random_string(20)}"
            println(deadVar)
        }}
"""
        return ""

    def _generate_simple_dead_block(self, language: str) -> str:
        """
        生成简单的死代码块（恒假条件）

        Args:
            language: 编程语言

        Returns:
            死代码块
        """
        if language == 'swift':
            return f"""
        // Dead code - always false
        if Double.random(in: 0...1) < 0.0 {{
            let _ = "{self._random_string(30)}"
        }}
"""
        elif language == 'java':
            return f"""
        // Dead code - always false
        if (Math.random() < 0.0) {{
            String unused = "{self._random_string(30)}";
        }}
"""
        elif language == 'kotlin':
            return f"""
        // Dead code - always false
        if (Math.random() < 0.0) {{
            val unused = "{self._random_string(30)}"
        }}
"""
        return ""

    def _random_string(self, length: int) -> str:
        """生成随机字符串"""
        import string
        return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

    def get_statistics(self) -> dict:
        """获取注入统计"""
        return {
            'injected_count': self.injected_count
        }
